package com.gy.controller.assistant.tools;

import com.gy.entity.result.Papers;
import com.gy.result.Result;
import com.gy.service.PapersService;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.ToolMemoryId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Component
public class PaperTool {
    private static final Logger log = LoggerFactory.getLogger(PaperTool.class);

    // 日期格式化器（新增论文用）
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE; // yyyy-MM-dd
    // memoryId拆分符（用户ID:会话ID）
    private static final String MEMORY_ID_SPLITTER = ":";

    // 合法收录检索列表（与前端表单一致）
    private static final List<String> LEGAL_INDEXING = List.of(
            "SCI", "SCIE", "SSCI", "ESCI", "自然指数杂志",
            "CSSCI", "CSSCI扩展版", "CSCD-C", "CSCD-E", "SCD",
            "AHCI", "EI", "CPCI-S (ISTP)", "CPCI-SSH (ISSHP)",
            "PKU (中文核心)", "科技核心", "国家级期刊", "省级期刊",
            "校内核心", "会议论文", "其他"
    );

    // DOI格式正则（简化版，匹配10.xxx/xxx）
    private static final Pattern DOI_PATTERN = Pattern.compile("10\\.\\d{4,}/[\\w\\-\\.]+");

    @Autowired
    private PapersService papersService;


    /**
     * 新增论文工具：将用户提供的论文信息保存到系统
     */
    @Tool(
            name = "新增论文工具",
            value = "帮用户新增论文到系统，必须先收集所有必填信息，缺失则逐一向用户追问：\n" +
                    "1. 论文标题（必填，不能为空，例如《AI在医疗领域的应用》）\n" +
                    "2. 论文类型（必填，只能是“期刊论文”“会议论文”“学位论文”中的一种）\n" +
                    "3. 刊物名称（必填，不能为空，例如“计算机学报”）\n" +
                    "4. 发表时间（必填，格式必须是yyyy-MM-dd，例如2024-05-20）\n" +
                    "5. 收录检索（必填，格式为列表，例如[\"SCI\"]，不能为空）\n" +
                    "可选信息（用户不提供则留空，无需追问）：\n" +
                    "- 论文PDF链接（例如https://xxx.pdf）\n" +
                    "- 备注（例如“2024年核心期刊发表”）\n" +
                    "追问规则：按上述顺序依次追问缺失的必填项，直到所有必填项收集完整。"
    )
    public String addPaper(
            @ToolMemoryId String memoryId,
            String title,
            String paperType,
            String journalName,
            String publishDate,
            List<String> indexing,
            String pdfUrl,
            String remarks
    ) {
        // 提取用户ID
        Long userId = extractUserIdFromMemoryId(memoryId);
        if (userId == null) {
            String errorMsg = "用户身份无效：memoryId格式错误或提取失败（memoryId=" + memoryId + "）";
            log.error(errorMsg);
            return errorMsg;
        }

        // 校验必填参数
        if (title == null || title.trim().isEmpty()) {
            return "论文标题不能为空（必填项）";
        }
        if (paperType == null || !List.of("期刊论文", "会议论文", "学位论文").contains(paperType)) {
            return "论文类型必填，只能是“期刊论文”“会议论文”“学位论文”中的一种";
        }
        if (journalName == null || journalName.trim().isEmpty()) {
            return "刊物名称不能为空（必填项）";
        }

        // 校验发表时间格式
        LocalDate publishLocalDate;
        try {
            publishLocalDate = LocalDate.parse(publishDate, DATE_FORMATTER);
        } catch (DateTimeParseException e) {
            log.error("发表时间格式错误，输入值={}，正确格式yyyy-MM-dd", publishDate, e);
            return "发表时间格式错误（必填项），必须是yyyy-MM-dd（如2024-05-20）";
        }

        // 校验收录检索合法性
        List<String> validIndexing = validatePaperIndexing(indexing);
        if (validIndexing.isEmpty()) {
            return "收录检索不能为空且必须包含合法值（合法值：" + String.join("、", LEGAL_INDEXING) + "）";
        }

        // 构建实体并保存
        try {
            Papers papers = new Papers();
            papers.setTitle(title.trim());
            papers.setPaperType(paperType);
            papers.setJournalName(journalName.trim());
            papers.setPublishDate(java.sql.Timestamp.valueOf(publishLocalDate.atStartOfDay()));
            papers.setIndexing(validIndexing); // 使用校验后的收录检索
            papers.setPdfPath(pdfUrl);
            papers.setRemarks(remarks);
            papers.setUserId(userId);

            Result result = papersService.savePapers(papers, userId);

            if (result.getCode() == 1) {
                String successMsg = "论文新增成功！标题：《" + title + "》，类型：" + paperType + "，用户ID：" + userId;
                log.info(successMsg);
                return successMsg;
            } else {
                String errorMsg = "论文新增失败：" + result.getMsg() + "（用户ID：" + userId + "）";
                log.error(errorMsg);
                return errorMsg;
            }
        } catch (Exception e) {
            String errorMsg = "新增论文系统异常（用户ID：" + userId + "，标题：" + title + "）";
            log.error(errorMsg, e);
            return errorMsg + "：" + e.getMessage();
        }
    }


    /**
     * 论文OCR文本清理：去除参考文献、正文等无关内容，保留关键信息
     */
    @Tool("清理论文OCR文本，去除参考文献、正文、页眉页脚，保留封面、目录、检索报告信息")
    public String cleanPaperOcrText(String ocrText) {
        if (ocrText == null) return "";
        // 1. 去除参考文献标识后的内容（如“参考文献”“References”后）
        String clean = Pattern.compile("(参考文献|References|REFERENCES).*$", Pattern.DOTALL)
                .matcher(ocrText)
                .replaceAll("");
        // 2. 保留摘要和关键词，去除中间可能的正文
        clean = Pattern.compile("(关键词|Keywords).*?(摘要|Abstract)", Pattern.DOTALL)
                .matcher(clean)
                .replaceAll("$1$2");
        // 3. 去除多余空格和特殊字符
        clean = clean.replaceAll("[^\\u4e00-\\u9fa5a-zA-Z0-9\\s:：,，;；.。=/\\-()（）]", "");
        clean = clean.replaceAll("\\s+", " ").trim();
        log.debug("清理后论文OCR文本长度：{}", clean.length());
        return clean;
    }


    /**
     * 校验收录检索合法性（过滤非法值，返回合法列表）
     */
    @Tool( "校验论文收录检索是否合法，返回合法列表，过滤非法值")
    public List<String> validatePaperIndexing(List<String> indexingList) {
        if (indexingList == null) return List.of();
        // 过滤不在合法列表中的值，忽略大小写
        return indexingList.stream()
                .map(String::trim)
                .filter(index -> LEGAL_INDEXING.stream().anyMatch(legal -> legal.equalsIgnoreCase(index)))
                .distinct() // 去重
                .collect(Collectors.toList());
    }


    /**
     * 校验DOI格式合法性
     */
    @Tool( "校验DOI号格式，合法返回原DOI，不合法返回null")
    public String validateDoi(String doi) {
        if (doi == null || doi.trim().isEmpty()) return null;
        String trimmedDoi = doi.trim();
        if (DOI_PATTERN.matcher(trimmedDoi).find()) {
            return trimmedDoi;
        } else {
            log.warn("非法DOI格式：{}", doi);
            return null;
        }
    }


    /**
     * 校验影响因子格式（必须为数字，支持小数）
     */
    @Tool( "校验影响因子格式，必须为数字（如3.102），返回字符串，不合法返回null")
    public String validateImpactFactor(String impactFactorStr) {
        if (impactFactorStr == null || impactFactorStr.trim().isEmpty()) return null;
        // 匹配数字（整数或小数）
        if (impactFactorStr.matches("^\\d+(\\.\\d+)?$")) {
            return impactFactorStr.trim();
        } else {
            log.warn("非法影响因子格式：{}", impactFactorStr);
            return null;
        }
    }


    /**
     * 从memoryId中提取userId（格式：userId:sessionId）
     */
    private Long extractUserIdFromMemoryId(String memoryId) {
        log.info("开始拆分memoryId提取userId，memoryId={}", memoryId);

        if (memoryId == null || memoryId.isEmpty()) {
            log.error("memoryId为空，无法提取userId");
            return null;
        }
        if (!memoryId.contains(MEMORY_ID_SPLITTER)) {
            log.error("memoryId格式错误，缺少分隔符'{}'（正确格式：userId{}sessionId），实际值={}",
                    MEMORY_ID_SPLITTER, MEMORY_ID_SPLITTER, memoryId);
            return null;
        }

        String[] parts = memoryId.split(MEMORY_ID_SPLITTER, 2);
        String userIdStr = parts[0].trim();
        if (userIdStr.isEmpty()) {
            log.error("memoryId中userId部分为空，实际值={}", memoryId);
            return null;
        }

        try {
            return Long.parseLong(userIdStr);
        } catch (NumberFormatException e) {
            log.error("userIdStr无法转换为数字，userIdStr={}，memoryId={}", userIdStr, memoryId, e);
            return null;
        }
    }
}
